C dla kaûdego (cz. 9.) ---------------------- PISANIA CIÂG DALSZY Zakoïczymy dziô rozpoczëte przed miesiâcem rozwaûania na temat czcionek. Listing, który dziô zaprezentujemy, nie powinien byê nowoôciâ. Myôlë, ûe pracowity Czytelnik po lekturze poprzedniego odcinka ma juû jakieô pojëcie o otwieraniu czcionek. Kamil Iskra, Dariusz Ûbik Funkcja OpenDiskFont() otwiera czcionkë najbardziej zbliûonâ do opisu, jednak nie zawsze dostëpna na dysku czcionka odpowiada naszym wymaganiom. W takim wypadku moûliwe jest wygenerowanie ûâdanych atrybutów. Sîuûy do tego funkcja: ULONG SetSoftStyle( struct RastPort *rp, ULONG style, ULONG enable ); Funkcja zmienia styl czcionki uûywanej przez RastPort "rp" na styl opisany za pomocâ parametru "style" (moûliwe pochylenie, pogrubienie i podkreôlenie -- patrz poprzednia czëôê). Funkcja zwraca flagi stylu, który udaîo sië uzyskaê. Argument "enable" jest maskâ bitowâ, zezwalajâcâ na zastosowanie poszczególnych atrybutów. W zaleûnoôci od upodobaï twórcy czcionki nie wszystkie atrybuty mogâ byê programowo generowane (bo na przykîad czcionka zostaîa od razu zaprojektowana jako pochylona), argument "enable" powinien mieê ustawione te bity, które odpowiadajâ moûliwym do generowania trybom. Aby uzyskaê informacje, które atrybuty sâ dozwolone, naleûy skorzystaê z funkcji: ULONG AskSoftStyle( struct RastPort *rp ); Funkcja ta zwraca wartoôê, która jest maskâ bitowâ wszystkich moûliwych atrybutów czcionki, uûywanej aktualnie w podanym jako argument RastPorcie. Informacje o stylach, które zostaîy wygenerowane, moûna znaleúê w polu "AlgoStyle" struktury "RastPort". Kwestië otwarcia czcionki i ustalenia jej stylu mamy juû za sobâ. Najwyûszy czas wziâê sië do pisania. Najprostszâ funkcjâ, piszâcâ po RastPorcie, jest zaprezentowana juû w czëôci szóstej funkcja z "graphics.library": LONG Text( struct RastPort *rp, STRPTR string, ULONG count ); Funkcja ta uznaje ustawienia RastPortu, takie jak kolory, tryb rysowania i, rzecz jasna, czcionkë. Poniewaû istniejâ czcionki proporcjonalne, okreôlenie dîugoôci napisu wykonanego takâ czcionkâ moûe byê kîopotliwe. W tym celu biblioteka graficzna zostaîa wyposaûona w funkcje, pozwalajâce wyliczyê rozmiary napisu. Pierwszâ i jednoczeônie najstarszâ jest: WORD TextLength( struct RastPort *rp, STRPTR string, ULONG count ); Funkcja ta okreôla, o ile punktów w poziomie przesunie sië kursor graficzny po wypisaniu w RastPorcie napisu, wskazywanego przez "string", o dîugoôci odnotowanej w argumencie "count". Informacja ta nie zawsze jest w peîni wystarczajâca, poniewaû w wypadku czcionek pochylonych wystëpujâ rozbieûnoôci pomiëdzy ostatnim zajëtym przez napis punktem a poîoûeniem kursora po umieszczeniu napisu (patrz rysunek -- czerwonymi krzyûykami oznaczono kursor graficzny przed i po umieszczeniu tekstu w RastPorcie). Kolejnâ funkcjâ, pomocnâ w okreôleniu rozmiarów napisu, jest TextExtent(). Pojawiîa sië ona w systemie operacyjnym 2.0: void TextExtent( struct RastPort *rp, STRPTR string, long count, struct TextExtent *textExtent ); Trzy pierwsze argumenty sâ analogiczne do argumentów funkcji TextLength(). Czwarty argument jest wskaúnikiem na strukturë "TextExtent", zdefiniowanâ w "graphics/text.h", w której zostanâ umieszczone rezultaty. struct TextExtent { UWORD te_Width; UWORD te_Height; struct Rectangle te_Extent; }; Po wywoîaniu funkcji struktura ta zostanie wypeîniona w sposób nastëpujâcy: "te_Width" -- zawiera të samâ wartoôê, którâ zwraca funkcja TextLength(), czyli przesuniëcie kursora graficznego, jakie spowoduje wypisanie napisu. "te_Height" -- zawiera wysokoôê napisu, czyli "tf_YSize" czcionki. Kolejne pole jest strukturâ "Rectangle", przeznaczonâ do opisu prostokâta: struct Rectangle { WORD MinX, MinY; WORD MaxX, MaxY; }; W naszym wypadku struktura ta opisuje obszar, który ulegnie zmianie po wypisaniu napisu. Wszystkie wspóîrzëdne sâ liczone wzglëdem obecnego poîoûenia kursora graficznego w RastPorcie, oznaczajâ wiëc: "te_Extent.MinX" -- odlegîoôê pomiëdzy pozycjâ "cp_x" kursora w RastPorcie a lewâ krawëdziâ prostokâta, zawierajâcego napis -- wartoôê ta bywa ujemna; "te_Extent.MinY" -- odlegîoôê pomiëdzy pozycjâ "cp_y" kursora (a wiëc liniâ bazowâ) a górnâ krawëdziâ prostokâta -- równieû bywa ujemna; "te_Extent.MaxX" -- odlegîoôê pomiëdzy pozycjâ "cp_x" kursora a prawâ krawëdziâ prostokâta; "te_Extent.MaxY" -- odlegîoôê pomiëdzy pozycjâ "cp_y" kursora (a wiëc liniâ bazowâ) a dolnâ krawëdziâ prostokâta. W szczególnym wypadku stosowania czcionek "normalnych" pole "te_Extent.MinX" wynosi 0. Wiem, ûe nie jest to oczywiste, wiëc proponujë przeanalizowaê rysunek. Kolorem zielonym zaznaczone sâ wspóîrzëdne, otrzymane po przesuniëciu kursora graficznego o wartoôci zapisane w strukturze "Rectangle". Linia górna jest wynikiem przesuniëcia kursora w pionie o wartoôê "MinY", linia dolna -- "MaxY", lewa -- "MinX", prawa -- "MaxX". Linia koloru niebieskiego jest wynikiem przesuniëcia kursora o wartoôê "te_Width". Caîkowita dîugoôê prostokâta, zawierajâcego napis, wynosi wiëc te_Extent.MaxX-te_Extent.MinX+1. Z wysokoôciâ jest analogicznie, moûna równieû skorzystaê z pola "tf_YSize" czcionki. Jeôli ktoô chciaîby narysowaê ramkë na zewnâtrz napisu, to wystarczy zmniejszyê o 1 pola "MinX" i "MinY" oraz zwiëkszyê o 1 "MaxX" i "MaxY". Dziëki zmianie wartoôci tych pól ramka bëdzie narysowana na zewnâtrz prostokâta zawierajâcego napis. Wykonanie ramki jest przedstawione w przykîadzie (funkcja border()). Za pomocâ funkcji TextExtent() moûna sprawdziê, ile liter danego napisu zmieôci sië w RastPorcie. Wystarczy umieôciê të funkcjë w pëtli zmniejszajâcej przy kaûdym obrocie wartoôê "count" i wykonujâcej sië aû do chwili, gdy napis zmieôci sië w ûâdanym obszarze. Poniewaû potrzeba taka zachodzi doôê czësto, powstaîo do tego celu narzëdzie systemowe. Funkcja TextFit(), bo o niej mowa, jako wynik dziaîania zwraca liczbë znaków, którâ moûna wpisaê do podanego obszaru. Wypeînia ona równieû podanâ strukturë "TextExtent", która zawiera dokîadnie te same informacje, co w wypadku poprzedniej funkcji. Jedyna róûnica polega na tym, ûe informacje te dotyczâ napisu o dîugoôci równej wartoôci zwróconej przez funkcjë. ULONG TextFit( struct RastPort *rp, STRPTR string, ULONG strLen, struct TextExtent *textExtent, struct TextExtent *constrainingExtent, long strDirection, ULONG constrainingBitWidth, ULONG constrainingBitHeight ); Argumenty "rp", "string", "strLen" oraz "textExtent" sâ analogiczne do argumentów poprzedniej funkcji. Argument "strDirection" ustala, w którâ stronë majâ byê naliczane znaki -- zwykle podaje sië 1, wtedy funkcja informuje, ile pierwszych liter napisu "string" sië zmieôci. Gdy poda sië -1, a jako "string" koniec napisu, wtedy funkcja wyliczy, ile ostatnich liter napisu sië zmieôci. Do funkcji naleûy przekazaê wymiary obszaru, na którym ma byê umieszczony napis. Wedle posiadanej przez nas dokumentacji wymiary te moûna przekazaê na dwa sposoby: albo podajâc wypeînionâ strukturë "TextExtend" jako parametr "constrainingExtent", albo podajâc tam NULL, a szerokoôê i wysokoôê w polach "constrainingBitWidth" i "constrainingBitHeight". Drugi sposób dziaîa bez zarzutu, jednak pierwszy jest zupeînie nie udokumentowany. Darek usiîowaî rozszyfrowaê, "co jest grane", eksperymentujâc, ale doszedî do dziwacznych wniosków, których nie zamierzamy tu prezentowaê. Polecamy wiëc uûywaê tylko drugiego sposobu, który zresztâ w praktyce w peîni wystarcza. Najwyûsza pora zaprezentowaê przykîad. W dzisiejszym listingu po raz pierwszy skorzystamy z biblioteki pochodzâcej z dysku. W takim wypadku koniecznie trzeba wziâê pod uwagë moûliwoôê zwrócenia NULL przez OpenLibrary() (bo np. uûytkownik mógî bibliotekë skasowaê z dysku). Prawdziwy program uûytkowy powinien poinformowaê o jej braku, nam w przykîadzie szkoda na to miejsca. W wypadku bibliotek, znajdujâcych sië w ROM-ie, takich jak "intuition" czy "graphics", moûna z czystym sumieniem zrezygnowaê ze sprawdzania, czy próba ich otwarcia zostaîa uwieïczona sukcesem, co teû czynië w przykîadzie. Przykîad oczekuje jednego parametru w linii argumentowej -- nazwy czcionki, którâ bëdzie "maltretowaî". W jednym z poprzednich odcinków obiecaîem, ûe pokaûë, jak obejôê sië bez "WFLG_GIMMEZEROZERO", wîaônie to robië: Struktura "Window" zawiera pola, w których zapisana jest szerokoôê poszczególnych ramek okna. Pola "BorderLeft", "BorderTop", "BorderRight", "BorderBottom" zawierajâ szerokoôci odpowiednio lewej, górnej, prawej i dolnej ramki. Aby nie "papraê" po ramkach, wystarczy pamiëtaê, ûe "dozwolony" obszar zaczyna sië poniûej górnej i na prawo od lewej ramki, oraz powyûej dolnej i na lewo od prawej. W przykîadzie korzystam ze struktury "Rectangle", w której na poczâtku odnotowujë wolny obszar okna, a nastëpnie sukcesywnie zmniejszam go, umieszczajâc w RastPorcie napisy. Moûe Was zastanawiaê, dlaczego sprawdzajâc, czy jest cokolwiek do napisania, sprawdzamy zarówno, czy TextFit() zwróciîa wartoôê niezerowâ, jak i to, czy za napisem bëdzie jeszcze przewidziane przez nas wolne miejsce. Powinien wîaôciwie wystarczyê ten pierwszy test. Wyglâda jednak na to, ûe funkcja TextFit() ma bîâd -- gdy "da" sië jej zbyt maîo miejsca, to czasami "wydaje" jej sië, ûe ma go w bród i "udziela nieprawdziwych informacji", naleûy wiëc zweryfikowaê otrzymane wyniki. W pëtli do-while zastosowaîem skrót, pozwalajâcy cyklicznie zmieniaê atrybuty czcionki. Skrót ten jest dokîadnie taki sam, jak w poprzednim listingu. Tamten dotyczyî trybu rysowania w RastPorcie. Na koniec przypominam, ûe polecenie preprocesora "#undef" powoduje "zapomnienie" o poprzedniej definicji makra.